package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.trade.OrderBasicDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author rui
 * @since 2024-07-10
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final LearningRecordMapper recordMapper;
    private final LearningLessonMapper learningLessonMapper;
    @Override
    public void addLearningLesson(OrderBasicDTO dto) {
        Long userId = dto.getUserId();
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(dto.getCourseIds());
        if(CollUtils.isEmpty(simpleInfoList)){
            return;
        }
        List<LearningLesson> lists = new ArrayList<>();
        for (CourseSimpleInfoDTO infoDTO : simpleInfoList) {
            LearningLesson learningLesson = new LearningLesson();
            learningLesson.setCourseId(infoDTO.getId());
            learningLesson.setUserId(userId);
            if(infoDTO.getValidDuration() != null){
                learningLesson.setCreateTime(LocalDateTime.now());
                //设置过期时间，单位是月
                learningLesson.setExpireTime(LocalDateTime.now()
                        .plusMonths(infoDTO.getValidDuration()));
            }
            lists.add(learningLesson);
        }
        this.saveBatch(lists);
    }

    @Override
    public PageDTO<LearningLessonVO> pageQuery(PageQuery pageQuery) {
        Page<LearningLesson> page;
        page = pageQuery.toMpPage("latest_learn_time", false);

        List<LearningLesson> learningLessons = lambdaQuery()
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .page(page)
                .getRecords();
        if(learningLessons.isEmpty()){
            return PageDTO.empty(page);
        }
        Set<Long> ids = learningLessons.stream()
                .map(LearningLesson::getCourseId)
                .collect(Collectors.toSet());
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(ids);
        if(CollUtils.isEmpty(simpleInfoList)){
            throw new BadRequestException("课程信息不存在");
        }
        Map<Long, CourseSimpleInfoDTO> cMap = simpleInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId,c->c));
        List<LearningLessonVO> list = new ArrayList<>(learningLessons.size());
        for (LearningLesson learningLesson : learningLessons) {
            LearningLessonVO lessonVO = BeanUtil.toBean(learningLesson, LearningLessonVO.class);
            CourseSimpleInfoDTO infoDTO = cMap.get(learningLesson.getCourseId());
            lessonVO.setCourseName(infoDTO.getName());
            lessonVO.setSections(infoDTO.getSectionNum());
            lessonVO.setCourseCoverUrl(infoDTO.getCoverUrl());
            list.add(lessonVO);
        }
        return PageDTO.of(page,list);
    }

    @Override
    public LearningLessonVO getByNow() {
        Long userId = UserContext.getUser();
        LearningLesson learningLesson = lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING)
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1").one();
        if(learningLesson == null){
            return null;
        }
        //获取课程详细信息,如封面、url、总章节数
        CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);

        if(courseInfoById == null){
            throw new BadRequestException("没有学习中的课表");
        }
        //获取课程对应id的数量
        Integer count = lambdaQuery()
                .eq(LearningLesson::getUserId,userId)
                .count();
        //封装返回结果
        LearningLessonVO lessonVO = BeanUtil.toBean(learningLesson, LearningLessonVO.class);
        lessonVO.setCourseAmount(count);
        lessonVO.setSections(courseInfoById.getSectionNum());
        lessonVO.setCourseCoverUrl(courseInfoById.getCoverUrl());
        //获取课程其他需要封装的属性
        List<Long> ids = Collections.singletonList(learningLesson.getLatestSectionId());
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(ids);
        if(!CollUtil.isEmpty(cataSimpleInfoDTOS)){
            lessonVO.setLatestSectionIndex(cataSimpleInfoDTOS.get(0).getCIndex());
            lessonVO.setLatestSectionName(cataSimpleInfoDTOS.get(0).getName());
        }
        lessonVO.setCourseName(courseInfoById.getName());
        return lessonVO;
    }

    @Override
    public void deleteByCourseId(Long courseId) {
        //获取用户id
        Long userId = UserContext.getUser();
        //获取要删除的课程在不在
        LearningLesson learningLesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if(learningLesson == null){
            throw new BizIllegalException("要删除的课程不存在");
        }
        //判断是否删的掉,能的话就删除
        //状态已经失效,直接删除
        if(learningLesson.getStatus().equals(LessonStatus.EXPIRED)){
            QueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id",userId).eq("course_id",courseId);
            remove(queryWrapper);
            log.info("课程id为{}，已经删除",courseId);
        }
    }

    @Override
    public Long isLessonValid(Long courseId) {
        Long userId = UserContext.getUser();
        LearningLesson learningLesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if(learningLesson == null){
            return null;
        }
        if(learningLesson.getExpireTime()!=null&&learningLesson.getExpireTime().isBefore(LocalDateTime.now())){
            return null;
        }
        return learningLesson.getId();
    }

    @Override
    public LearningLessonVO getByCourseId(Long courseId) {
        Long user = UserContext.getUser();
        LearningLesson learningLesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, user)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if(learningLesson != null){
            return BeanUtil.toBean(learningLesson, LearningLessonVO.class);
        }
        return null;
    }

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        //统计该课程学习的人数
        Integer count = this.lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .count();
        return count;
    }

    @Override
    public void createLearningPlan(Long courseId, Integer freq) {
        //获取用户信息
        Long user = UserContext.getUser();
        //获取课程信息
        LearningLesson learningLesson = lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, user)
                .one();
        if(learningLesson == null){
            throw new BizIllegalException("创建学习计划的课表不存在");
        }
        //更新课表信息，更新每周学习频率、学习计划字段状态
        boolean success = lambdaUpdate()
                .set(LearningLesson::getWeekFreq, freq)
                .set(learningLesson.getPlanStatus() == PlanStatus.NO_PLAN,LearningLesson::getPlanStatus,PlanStatus.PLAN_RUNNING)
                .eq(LearningLesson::getId, learningLesson.getId())
                .update();
        if(!success){
            throw new DbException("更新学习计划失败");
        }
    }

    @Override
    public LearningPlanPageVO queryLearningPlans(PageQuery pageQuery) {
        //获取当前登录用户id
        Long userId = UserContext.getUser();
        //获取当前登录用户的符合条件的所有课程信息
        List<LearningLesson> lessons = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(pageQuery.toMpPage("latest_learn_time", false))
                .getRecords();
        if(lessons == null){
            return null;
        }
        //获取本周起始时间
        LocalDate now = LocalDate.now();
        LocalDateTime begin = DateUtils.getWeekBeginTime(now);
        LocalDateTime end = DateUtils.getWeekEndTime(now);
        //本周计划学习小节数量
        Integer weekFinished = recordMapper.selectCount(new LambdaQueryWrapper<LearningRecord>()
                .gt(LearningRecord::getFinishTime,begin)
                .lt(LearningRecord::getFinishTime,end)
                .eq(LearningRecord::getUserId,userId)
                .eq(LearningRecord::getFinished,true));

        //获取本周计划总的已学完小节数量
        Integer weekTotalPlan = learningLessonMapper.numByWeekPlan(userId) == null? 0:learningLessonMapper.numByWeekPlan(userId);
        //本周学习积分 todo
        //远程掉用course获取总小节数量,课程名称
        List<Long> ids = lessons.stream()
                .map(LearningLesson::getCourseId)
                .collect(Collectors.toList());
        List<CourseSimpleInfoDTO> infoList = courseClient.getSimpleInfoList(ids);
        if (CollUtils.isEmpty(infoList)) {
            // 课程不存在，无法添加
            throw new BadRequestException("课程信息不存在！");
        }
        Map<Long, CourseSimpleInfoDTO> map = infoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        //获取leaning_record本周学习的id，小节数量列表，便于后续封装
        List<LearningRecord> learningRecords = recordMapper.selectList(new QueryWrapper<LearningRecord>()
                .select("lesson_id as lessonId", "count(*) as userId")
                .eq("finished", true)
                .eq("user_id", userId)
                .between("finish_time", begin, end)
                .groupBy("lesson_id"));
        Map<Long, Long> idAndNums = learningRecords.stream().collect(Collectors.toMap(LearningRecord::getLessonId, LearningRecord::getUserId));

        //封装返回结果
        LearningPlanPageVO planPageVO = new LearningPlanPageVO();
        planPageVO.setWeekTotalPlan(weekTotalPlan);
        planPageVO.setWeekFinished(weekFinished);
        List<LearningPlanVO> planVOS = new ArrayList<>(lessons.size());

        for (LearningLesson lesson : lessons) {
            LearningPlanVO planVO = BeanUtil.toBean(lesson, LearningPlanVO.class);
            //获取课程名称跟总小节数量
            CourseSimpleInfoDTO infoDTO = map.get(lesson.getCourseId());
            if(infoDTO != null){
                planVO.setSections(infoDTO.getSectionNum());
                planVO.setCourseName(infoDTO.getName());
            }
            //本周学习的小节数量
            planVO.setWeekLearnedSections(idAndNums.get(lesson.getId()) == null ? 0 : idAndNums.get(lesson.getId()).intValue());

            planVOS.add(planVO);
        }
        planPageVO.setList(planVOS);
        return planPageVO;
    }
}
